package com.alinesno.cloud.compoment.generate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alinesno.cloud.compoment.generate.generator.AutoGenerator;
import com.alinesno.cloud.compoment.generate.generator.InjectionConfig;
import com.alinesno.cloud.compoment.generate.generator.PropertiesUtil;
import com.alinesno.cloud.compoment.generate.generator.config.DataSourceConfig;
import com.alinesno.cloud.compoment.generate.generator.config.GlobalConfig;
import com.alinesno.cloud.compoment.generate.generator.config.PackageConfig;
import com.alinesno.cloud.compoment.generate.generator.config.StrategyConfig;
import com.alinesno.cloud.compoment.generate.generator.config.rules.DbType;
import com.alinesno.cloud.compoment.generate.generator.config.rules.NamingStrategy;
import com.alinesno.cloud.compoment.generate.generator.tools.GeneratorTool;

/**
 * 代码生成工具类
 * @author WeiXiaoJin
 * @date 2017年9月16日
 */
public abstract class Generator {

	public final Logger logger = LoggerFactory.getLogger(this.getClass());

	public String feiginServer = "" ;  // 服务名称，用于feigin服务调用
	public DbType dbType = DbType.MYSQL ; /* 数据库类型 */
	public String[] tablePrefix = {} ; /* 表前缀 */
	public String[] tableNames; /* 目标表 */
	public List<String> arr = new ArrayList<String>();
	public String parentPackage = ""; /* 父包名 */
	private String artifactId ; // 模块名称 
	public String moduleName = ""; /* 模块名 */
	public String[] superField  = new String[] {
			"id","fieldProp","addTime","deleteTime","updateTime","hasDelete","hasStatus","deleteManager" , "tenantId" , "applicationId" , 
			"id","field_prop","add_time","delete_time","update_time","has_delete","has_status","delete_manager" , "application_id" , "tenant_id" , 
			"operator_id" , "last_update_operator_id" , "field_id" , "addtime" , "department_id"
			} ;  // 公共字段  

	/**
	 * soa模块前缀
	 */
	public static String SOA_MODULE_PREFIX = "";
	
	// 全局配置
	public GlobalConfig gc = new GlobalConfig();
	
	// 数据源配置
	public DataSourceConfig dsc = new DataSourceConfig();
	
	public String bootPrefix = PropertiesUtil.getString("code.boot.prefix") ; 
	public String outputDir = PropertiesUtil.getString("code.outputdir") ; 
	public String author = PropertiesUtil.getString("code.author") ; 

	public String dbDriverName = null ; 
	public String dbUsername = null ; 
	public String dbPwd = null ; 
	public String dbUrl = null ; 
	public String abcPath = null ; 
	
	public String springApplicationName ; 
	public String serverPort ; 
	public String articleId ; 
	public String groupId ; 
	
	public boolean isOpenFile = false ;  // 默认不打开输出目录 

	private String superRepositoryClassName = "" ; 
	private String superServiceClassName = "" ; 
	private String superServiceImplClassName = "" ; 
	private String superEntityClassName = "" ; 
	private String superRestfulClassName = "" ; 
	private String superFeignClassName = "" ; 
	private String superControllerClassName = "" ; 
	
	/**
	 * 初始化参数
	 */
	protected void initParam(String dataSourceType) {
	
		if(StringUtils.isNotBlank(dataSourceType)) {
			dbDriverName = PropertiesUtil.getString("alinesno.database."+dataSourceType+".driver") ; 
			dbUsername = PropertiesUtil.getString("alinesno.database."+dataSourceType+".username") ; 
			dbPwd = PropertiesUtil.getString("alinesno.database."+dataSourceType+".password") ; 
			dbUrl = PropertiesUtil.getString("alinesno.database."+dataSourceType+".url") ; 
		}
		
		// isOpenFile = Boolean.parseBoolean(PropertiesUtil.getString("code,outputdir.open")) ;

		if(StringUtils.isBlank(abcPath)) {
			abcPath = PropertiesUtil.getString("code.outputdir")  ; 
		}
	
		gc.setOutputDir(outputDir) ; 
		gc.setAuthor(author) ; 
		gc.setOpen(this.isOpenFile()) ; 
		
		// 数据库源
		dsc.setDriverName(dbDriverName) ; 
		dsc.setUsername(dbUsername) ; 
		dsc.setPassword(dbPwd) ; 
		dsc.setUrl(dbUrl) ; 
	
		springApplicationName = this.getArtifactId() ; 
		serverPort = StringUtils.isBlank(serverPort)?"24001":serverPort ; 
	}
	
	/**
	 * <p>
	 * 生成演示
	 * </p>
	 */
	public void generator(String dataSource) {

		initParam(dataSource);
		initTableName();

		if (tablePrefix == null) {
			logger.warn("table prefix 为空");
		}

		if (SOA_MODULE_PREFIX == null) {
			logger.warn("SOA_MODULE_PREFIX 为空");
		}

		if(arr != null && arr.size() > 0){
			tableNames = new String[arr.size()+tableNames.length];
			for (int i = 0; i < arr.size(); i++) {
				tableNames[i] = arr.get(i);
			}
		}

		final AutoGenerator mpg = new AutoGenerator(abcPath);

		gc.setFileOverride(true);
		gc.setActiveRecord(true);
		gc.setEnableCache(false);// XML 二级缓存
		gc.setBaseResultMap(true);// XML ResultMap
		gc.setBaseColumnList(false);// XML columList

		feiginServer = this.getArtifactId() ;  // 转换命名方式 
		groupId = (this.getArtifactId().replace("_", ".").replace("-", ".")) ;  // StringUtils.isBlank(groupId)?(parentPackage + "." + this.buildModelName(moduleName,feiginServer).replace("/", ".")):groupId ; 
		articleId = this.getArtifactId() ; // StringUtils.isBlank(articleId)?feiginServer:articleId ; 

		mpg.setGlobalConfig(gc);

		dsc.setDbType(dbType);
		mpg.setDataSource(dsc);

		// 策略配置
		final StrategyConfig strategy = new StrategyConfig();
		strategy.setTablePrefix(tablePrefix);// 此处可以修改为您的表前缀
		
		// 持久层
		strategy.setSuperRepositoryClass(this.getSuperRepositoryClassName()) ; //"com.alinesno.cloud.common.core.orm.repository.IBaseJpaRepository");
		strategy.setIdKeyType("String");
		
		// 服务
		strategy.setSuperServiceClass(this.getSuperServiceClassName()) ; //"com.alinesno.cloud.common.core.services.IBaseService");
		strategy.setSuperServiceImplClass(this.getSuperServiceImplClassName()) ; //"com.alinesno.cloud.common.core.services.impl.IBaseServiceImpl");
		strategy.setSuperEntityClass(this.getSuperEntityClassName()) ; //"com.alinesno.cloud.common.core.orm.entity.BaseEntity");
		
		// Rest接口
		strategy.setSuperRestControllerClass(this.getSuperRestfulClassName()) ; //"com.alinesno.cloud.common.core.rest.BaseRestController") ; 
		
		// boot 接口
		if(StringUtils.isNotBlank(feiginServer)) {
			bootPrefix = GeneratorTool.toUpperCaseFirstOne((GeneratorTool.lineToHump2(feiginServer))) ; 
		}
		logger.info("bootPrefix:{}" , bootPrefix);
		strategy.setBootPrefix(bootPrefix);
		
		// Feigin接口
		strategy.setSuperFeiginDtoClass("com.alinesno.cloud.common.facade.feign.BaseDto") ; 
		strategy.setFeiginServer(feiginServer);
			
		//前端
		strategy.setControllerMappingHyphenStyle(true) ;
		strategy.setSuperControllerClass(this.getSuperControllerClassName()) ; //"com.alinesno.training.common.base.BaseController");
		
		strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
		strategy.setInclude(tableNames); // 需要生成的表
		
		strategy.setSuperEntityColumns(superField) ; 
		
		mpg.setStrategy(strategy);

		// 包配置
		final PackageConfig pc = new PackageConfig();
		pc.setParent(parentPackage);
		pc.setModuleName(buildModelName(moduleName , feiginServer));
		pc.setController("controller");
		
		// yml and pom.xml
		pc.setSpringApplicationName(springApplicationName); 
		pc.setServerPort(serverPort);
		pc.setArticleId(articleId);
		pc.setGroupId(groupId);
		
		pc.setDatabaseDriverClass(dsc.getDriverName());
		pc.setDatabaseUrl(dsc.getUrl());
		pc.setDatabaseUsername(dsc.getUsername());
		pc.setDatabasePassword(dsc.getPassword()); 
		pc.setAbcPath(abcPath); 
		
		gc.setModuleName(pc.getModuleName());
		mpg.setPackageInfo(pc);

		// 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
		final InjectionConfig cfg = new InjectionConfig() {
			@Override
			public void initMap() {
				final Map<String, Object> map = new HashMap<String, Object>();
				map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
				this.setMap(map);
			}
		};
		mpg.setCfg(cfg);
		mpg.execute(pc);
		logger.debug("代码生成成功.");

		// 打印注入设置
		System.err.println(mpg.getCfg().getMap().get("abc"));
	}

	/**
	 * 创建模块名称
	 * @param moduleName
	 * @return
	 */
	protected String buildModelName(String moduleName , String feiginServer) {
		if(StringUtils.isBlank(moduleName)) {
			if(feiginServer != null) {
				String p = feiginServer.replace("alinesno-cloud-", "").replace("-", "/") ; 
				moduleName = p ; 
			}
		}
		logger.debug("moduleName:{}" , moduleName) ; 
		return moduleName ; 
	}

	/**
	 * 数组转换成集合
	 * @param tableNames
	 * @return
	 */
	public List<String> toArray(String[] tableNames) {
		List<String> arr = new ArrayList<String>() ; 
		for(String s :tableNames) {
			arr.add(s) ;
		}
		return arr ;
	}

	/**
	 * 
	 */
	public abstract void initTableName();

	public String getFeiginServer() {
		return feiginServer;
	}

	public void setFeiginServer(String feiginServer) {
		this.feiginServer = feiginServer;
	}

	public DbType getDbType() {
		return dbType;
	}

	public void setDbType(DbType dbType) {
		this.dbType = dbType;
	}

	public String[] getTablePrefix() {
		return tablePrefix;
	}

	public void setTablePrefix(String[] tablePrefix) {
		this.tablePrefix = tablePrefix;
	}

	public String[] getTableNames() {
		return tableNames;
	}

	public void setTableNames(String[] tableNames) {
		this.tableNames = tableNames;
	}

	public List<String> getArr() {
		return arr;
	}

	public void setArr(List<String> arr) {
		this.arr = arr;
	}

	public String getParentPackage() {
		return parentPackage;
	}

	public void setParentPackage(String parentPackage) {
		this.parentPackage = parentPackage;
	}

	public String getModuleName() {
		return moduleName;
	}

	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;
	}

	public String[] getSuperField() {
		return superField;
	}

	public void setSuperField(String[] superField) {
		this.superField = superField;
	}

	public static String getSOA_MODULE_PREFIX() {
		return SOA_MODULE_PREFIX;
	}

	public static void setSOA_MODULE_PREFIX(String sOA_MODULE_PREFIX) {
		SOA_MODULE_PREFIX = sOA_MODULE_PREFIX;
	}

	public GlobalConfig getGc() {
		return gc;
	}

	public void setGc(GlobalConfig gc) {
		this.gc = gc;
	}

	public DataSourceConfig getDsc() {
		return dsc;
	}

	public void setDsc(DataSourceConfig dsc) {
		this.dsc = dsc;
	}

	public String getBootPrefix() {
		return bootPrefix;
	}

	public void setBootPrefix(String bootPrefix) {
		this.bootPrefix = bootPrefix;
	}

	public String getOutputDir() {
		return outputDir;
	}

	public void setOutputDir(String outputDir) {
		this.outputDir = outputDir;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getDbDriverName() {
		return dbDriverName;
	}

	public void setDbDriverName(String dbDriverName) {
		this.dbDriverName = dbDriverName;
	}

	public String getDbUsername() {
		return dbUsername;
	}

	public void setDbUsername(String dbUsername) {
		this.dbUsername = dbUsername;
	}

	public String getDbPwd() {
		return dbPwd;
	}

	public void setDbPwd(String dbPwd) {
		this.dbPwd = dbPwd;
	}

	public String getDbUrl() {
		return dbUrl;
	}

	public void setDbUrl(String dbUrl) {
		this.dbUrl = dbUrl;
	}

	public String getAbcPath() {
		return abcPath;
	}

	public void setAbcPath(String abcPath) {
		this.abcPath = abcPath;
	}

	public String getSpringApplicationName() {
		return springApplicationName;
	}

	public void setSpringApplicationName(String springApplicationName) {
		this.springApplicationName = springApplicationName;
	}

	public String getServerPort() {
		return serverPort;
	}

	public void setServerPort(String serverPort) {
		this.serverPort = serverPort;
	}

	public String getArticleId() {
		return articleId;
	}

	public void setArticleId(String articleId) {
		this.articleId = articleId;
	}

	public String getGroupId() {
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public boolean isOpenFile() {
		return isOpenFile;
	}

	public void setOpenFile(boolean isOpenFile) {
		this.isOpenFile = isOpenFile;
	}

	public String getSuperRepositoryClassName() {
		return superRepositoryClassName;
	}

	public void setSuperRepositoryClassName(String superRepositoryClassName) {
		this.superRepositoryClassName = superRepositoryClassName;
	}

	public String getSuperServiceClassName() {
		return superServiceClassName;
	}

	public void setSuperServiceClassName(String superServiceClassName) {
		this.superServiceClassName = superServiceClassName;
	}

	public String getSuperServiceImplClassName() {
		return superServiceImplClassName;
	}

	public void setSuperServiceImplClassName(String superServiceImplClassName) {
		this.superServiceImplClassName = superServiceImplClassName;
	}

	public String getSuperEntityClassName() {
		return superEntityClassName;
	}

	public void setSuperEntityClassName(String superEntityClassName) {
		this.superEntityClassName = superEntityClassName;
	}

	public String getSuperRestfulClassName() {
		return superRestfulClassName;
	}

	public void setSuperRestfulClassName(String superRestfulClassName) {
		this.superRestfulClassName = superRestfulClassName;
	}

	public String getSuperFeignClassName() {
		return superFeignClassName;
	}

	public void setSuperFeignClassName(String superFeignClassName) {
		this.superFeignClassName = superFeignClassName;
	}

	public String getSuperControllerClassName() {
		return superControllerClassName;
	}

	public void setSuperControllerClassName(String superControllerClassName) {
		this.superControllerClassName = superControllerClassName;
	}

	public Logger getLogger() {
		return logger;
	}

	public String getArtifactId() {
		return artifactId;
	}

	public void setArtifactId(String artifactId) {
		this.artifactId = artifactId;
	}
	
}
